package structure;

public class parser {

	private parsingTable parsingTable;
	private String input;
	private stack stack;
	private String head;
	private int headBegin;
	private int headEnd;
	
	public parser(parsingTable parsingTable, String input){
		
		this.parsingTable= parsingTable;
		this.input= input;
		this.stack= new stack();
		//all'inizio solo q0 nello stack
		for(state st :this.parsingTable.getPowerset().getStates()){
			
			if(st.isStart()){
				
				this.stack.push(st.getLabel());
			}
		}
		this.headBegin= 0;
		this.headEnd= 1;
		this.head= this.input.substring(headBegin, headEnd);
	}
	
	//shift & goto
	public boolean shiftGoto(int row, int col){
		
		String action= this.parsingTable.getTable().get(row).get(col);
		if(!action.equals(" ")){

			String go= action.substring(3);//sh q0 prendo solo q0
			//System.out.println("SH: " + action);
			if(action.substring(0, 2).equals("sh")){

				//pusho la a e poi lo stato
				this.stack.push(this.head);
				this.stack.push(go);
				this.shift();
			}
			
			return true;
		}
		else
			return false;
		
	}
	//
	
	//shift
	public void shift(){
		
		//ALERT
		if(this.headBegin < this.input.length()-1){

			this.headBegin++;
			this.headEnd++;
			this.head= this.input.substring(headBegin, headEnd);
			//System.out.println("top= " + this.stack.topOfTheStack() + " head= " + this.head);
		}
		
	}
	
	//accept
	private boolean accept(int row, int col){
		
		if(this.parsingTable.getTable().get(row).get(col).equals("acc"))
			return true;
		
		return false;
	}
	//
	
	//goto
	
	//
	
	//reduce & goto
	public boolean reduceGoto(int row, int col){

		String action= this.parsingTable.getTable().get(row).get(col);
		if(!action.equals(" ")){

			String index= action.substring(4, 5);//red 4 prendo solo 4
			//System.out.println("RED: " + action);
			if(action.substring(0, 3).equals("red")){
				int i= Integer.valueOf(index);
				
				String leftside= this.parsingTable.getPowerset().getEnumGrammar().getLeftside().get(i);
				String rightside= this.parsingTable.getPowerset().getEnumGrammar().getRightside().get(i);
				
		
				int begin= rightside.length()-1;
				int end= begin + 1;
				boolean stop= false;
				while(!stop){

					String toRemove= rightside.substring(begin,  end);
					//System.out.println("toRemove= " + toRemove);
					//almeno una pop devo farla
					//this.stack.pop();
					//controllo che non sia epsilon
					if(this.stack.topOfTheStack().equals(toRemove) && !toRemove.equals("e")){

						this.stack.pop();
						if(begin > 0){
							begin--;
							end= begin+1;
						}
						else{

							//this.stack.pop();
							stop= true;
						}
					}
					else if(toRemove.equals("e"))
						stop=true;
					else{
						this.stack.pop();
					}
					
				}
				String oldTop= this.stack.topOfTheStack();
				this.stack.push(leftside);
				
				//System.out.println("old top= " + oldTop + ", leftside= " + leftside);
				row= this.parsingTable.getRowIndex(oldTop);
				col= this.parsingTable.getColIndex(leftside);
				
				this.stack.push(this.parsingTable.getTable().get(row).get(col));
					
			}
			
			return true;
		}
		else{
			return false;
		}
	}
	//
	
	public void parsing(){
		
		boolean stop= false;
		while(!stop){
			String label= this.stack.topOfTheStack();
			int row= this.parsingTable.getRowIndex(label);
			int col= this.parsingTable.getColIndex(this.head);
			//this.stack.printItAll();
			

			if(this.accept(row, col)){
				
				System.out.println("la parola è accettata.");
				stop= true;
			}
			else{

				if(!this.shiftGoto(row, col)){

					System.out.println("la parola non è accettata.");
					stop= true;
				}
				else if(!this.reduceGoto(row, col)){

					System.out.println("la parola non è accettata.");
					stop= true;
				}
				
			}
			
		}
			
	}
}
